#!/bin/bash

# 端口冲突检查和清理脚本
# 用于检查认证服务端口是否被占用，并提供清理选项

set -e

# 脚本配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# 认证服务配置
AUTH_SERVICE_PORT=8008
API_GATEWAY_PORT=8080

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

# 打印横幅
print_banner() {
    echo -e "${BLUE}"
    cat << 'EOF'
    ╔══════════════════════════════════════════════════════════════╗
    ║                    端口冲突检查工具                           ║
    ║                   Port Conflict Checker                     ║
    ║                                                              ║
    ║  版本: 1.0.0                                                 ║
    ║  作者: 29108                                                 ║
    ║  日期: 2025/8/2                                              ║
    ╚══════════════════════════════════════════════════════════════╝
EOF
    echo -e "${NC}"
}

# 检查端口占用
check_port() {
    local port=$1
    local service_name=$2
    
    log_info "检查端口 $port ($service_name)..."
    
    # 使用lsof检查端口占用
    local lsof_result=""
    if command -v lsof >/dev/null 2>&1; then
        lsof_result=$(lsof -i :$port 2>/dev/null || true)
    fi
    
    # 使用netstat检查端口占用
    local netstat_result=""
    if command -v netstat >/dev/null 2>&1; then
        netstat_result=$(netstat -tlnp 2>/dev/null | grep ":$port " || true)
    fi
    
    # 使用ss检查端口占用
    local ss_result=""
    if command -v ss >/dev/null 2>&1; then
        ss_result=$(ss -tlnp 2>/dev/null | grep ":$port " || true)
    fi
    
    if [[ -n "$lsof_result" || -n "$netstat_result" || -n "$ss_result" ]]; then
        log_warn "端口 $port 被占用:"
        
        if [[ -n "$lsof_result" ]]; then
            echo -e "${YELLOW}lsof 结果:${NC}"
            echo "$lsof_result"
        fi
        
        if [[ -n "$netstat_result" ]]; then
            echo -e "${YELLOW}netstat 结果:${NC}"
            echo "$netstat_result"
        fi
        
        if [[ -n "$ss_result" ]]; then
            echo -e "${YELLOW}ss 结果:${NC}"
            echo "$ss_result"
        fi
        
        return 1
    else
        log_info "端口 $port 未被占用"
        return 0
    fi
}

# 查找并终止进程
kill_processes_on_port() {
    local port=$1
    local service_name=$2
    
    log_warn "尝试终止占用端口 $port 的进程..."
    
    # 获取占用端口的进程ID
    local pids=""
    
    if command -v lsof >/dev/null 2>&1; then
        pids=$(lsof -ti :$port 2>/dev/null || true)
    fi
    
    if [[ -z "$pids" ]] && command -v netstat >/dev/null 2>&1; then
        pids=$(netstat -tlnp 2>/dev/null | grep ":$port " | awk '{print $7}' | cut -d'/' -f1 | grep -v '-' || true)
    fi
    
    if [[ -z "$pids" ]] && command -v ss >/dev/null 2>&1; then
        pids=$(ss -tlnp 2>/dev/null | grep ":$port " | sed 's/.*pid=\([0-9]*\).*/\1/' || true)
    fi
    
    if [[ -n "$pids" ]]; then
        for pid in $pids; do
            if [[ "$pid" =~ ^[0-9]+$ ]]; then
                log_info "终止进程 PID: $pid"
                
                # 获取进程信息
                local process_info=$(ps -p $pid -o pid,ppid,cmd --no-headers 2>/dev/null || echo "进程信息不可用")
                log_info "进程信息: $process_info"
                
                # 先尝试优雅终止
                if kill -TERM $pid 2>/dev/null; then
                    log_info "发送 SIGTERM 信号到进程 $pid"
                    sleep 2
                    
                    # 检查进程是否还在运行
                    if kill -0 $pid 2>/dev/null; then
                        log_warn "进程 $pid 仍在运行，发送 SIGKILL 信号"
                        kill -KILL $pid 2>/dev/null || true
                    fi
                else
                    log_error "无法终止进程 $pid (可能需要sudo权限)"
                fi
            fi
        done
    else
        log_info "未找到占用端口 $port 的进程"
    fi
}

# 检查认证服务进程
check_auth_service_processes() {
    log_info "检查认证服务相关进程..."
    
    local auth_processes=$(ps aux | grep -E "(auth_service|AuthService)" | grep -v grep || true)
    
    if [[ -n "$auth_processes" ]]; then
        log_warn "发现认证服务相关进程:"
        echo "$auth_processes"
        return 1
    else
        log_info "未发现认证服务相关进程"
        return 0
    fi
}

# 清理认证服务进程
cleanup_auth_service_processes() {
    log_warn "清理认证服务相关进程..."

    # 查找认证服务进程（更精确的匹配）
    local pids=$(ps aux | grep -E "auth_service" | grep -v grep | grep -v "check_port_conflicts" | awk '{print $2}' || true)

    if [[ -n "$pids" ]]; then
        log_warn "发现 $(echo $pids | wc -w) 个认证服务进程"

        for pid in $pids; do
            if [[ "$pid" =~ ^[0-9]+$ ]]; then
                # 获取进程信息
                local process_info=$(ps -p $pid -o pid,ppid,cmd --no-headers 2>/dev/null || echo "进程信息不可用")
                log_info "终止进程 PID: $pid - $process_info"

                # 先尝试优雅终止
                if kill -TERM $pid 2>/dev/null; then
                    log_info "发送 SIGTERM 到进程 $pid"
                    sleep 1

                    # 检查进程是否还在运行
                    if kill -0 $pid 2>/dev/null; then
                        log_warn "进程 $pid 仍在运行，发送 SIGKILL"
                        kill -KILL $pid 2>/dev/null || true
                        sleep 1
                    fi

                    # 再次检查
                    if kill -0 $pid 2>/dev/null; then
                        log_error "无法终止进程 $pid"
                    else
                        log_info "进程 $pid 已终止"
                    fi
                else
                    log_error "无法发送信号到进程 $pid (可能需要sudo权限)"
                fi
            fi
        done

        # 等待进程完全退出
        log_info "等待进程完全退出..."
        sleep 3

        # 再次检查是否还有残留进程
        local remaining_pids=$(ps aux | grep -E "auth_service" | grep -v grep | grep -v "check_port_conflicts" | awk '{print $2}' || true)
        if [[ -n "$remaining_pids" ]]; then
            log_error "仍有残留进程: $remaining_pids"
            log_warn "尝试强制终止残留进程..."
            for pid in $remaining_pids; do
                if [[ "$pid" =~ ^[0-9]+$ ]]; then
                    kill -KILL $pid 2>/dev/null || true
                fi
            done
        else
            log_info "所有认证服务进程已清理完成"
        fi
    else
        log_info "未找到认证服务进程"
    fi
}

# 主函数
main() {
    print_banner
    
    local action="${1:-check}"
    
    case "$action" in
        check)
            log_info "=== 端口占用检查 ==="
            
            local conflicts=0
            
            if ! check_port $AUTH_SERVICE_PORT "认证服务"; then
                conflicts=$((conflicts + 1))
            fi
            
            if ! check_port $API_GATEWAY_PORT "API网关"; then
                conflicts=$((conflicts + 1))
            fi
            
            if ! check_auth_service_processes; then
                conflicts=$((conflicts + 1))
            fi
            
            if [[ $conflicts -eq 0 ]]; then
                log_info "=== 检查完成：无端口冲突 ==="
            else
                log_warn "=== 检查完成：发现 $conflicts 个冲突 ==="
                log_info "运行 '$0 clean' 来清理冲突"
            fi
            ;;
            
        clean)
            log_warn "=== 清理端口冲突 ==="
            
            cleanup_auth_service_processes
            kill_processes_on_port $AUTH_SERVICE_PORT "认证服务"
            
            # 等待一段时间让进程完全退出
            sleep 3
            
            # 再次检查
            log_info "=== 清理后检查 ==="
            check_port $AUTH_SERVICE_PORT "认证服务"
            check_auth_service_processes
            ;;
            
        help)
            echo "用法: $0 [check|clean|help]"
            echo ""
            echo "命令:"
            echo "  check  检查端口冲突 (默认)"
            echo "  clean  清理端口冲突"
            echo "  help   显示帮助信息"
            echo ""
            echo "示例:"
            echo "  $0         # 检查端口冲突"
            echo "  $0 check   # 检查端口冲突"
            echo "  $0 clean   # 清理端口冲突"
            ;;
            
        *)
            log_error "未知命令: $action"
            echo "运行 '$0 help' 查看帮助信息"
            exit 1
            ;;
    esac
}

# 执行主函数
main "$@"
